﻿// Copyright (c) .NET Foundation and Contributors. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.

using Microsoft.CodeAnalysis;
using Roslynator.FindSymbols;

namespace Roslynator.Documentation;

internal abstract class AbstractSymbolDefinitionTextWriter : SymbolDefinitionWriter
{
    protected AbstractSymbolDefinitionTextWriter(
        SymbolFilterOptions filter,
        DefinitionListFormat format = null,
        SymbolDocumentationProvider documentationProvider = null,
        INamedTypeSymbol hierarchyRoot = null) : base(filter, format, documentationProvider, hierarchyRoot)
    {
    }

    protected abstract void WriteIndentation();

    public override void WriteStartDocument()
    {
    }

    public override void WriteEndDocument()
    {
    }

    public override void WriteStartAssemblies()
    {
    }

    public override void WriteEndAssemblies()
    {
    }

    public override void WriteStartAssembly(IAssemblySymbol assemblySymbol)
    {
        WriteIndentation();
    }

    public override void WriteAssemblyDefinition(IAssemblySymbol assemblySymbol)
    {
        Write("assembly ");
        WriteLine(assemblySymbol.Identity.ToString());
        IncreaseDepth();

        if (Format.Includes(SymbolDefinitionPartFilter.AssemblyAttributes))
            WriteAttributes(assemblySymbol);
    }

    public override void WriteEndAssembly(IAssemblySymbol assemblySymbol)
    {
        DecreaseDepth();
    }

    public override void WriteAssemblySeparator()
    {
        if (Format.Includes(SymbolDefinitionPartFilter.AssemblyAttributes))
            WriteLine();
    }

    public override void WriteEndNamespaces()
    {
    }

    public override void WriteStartNamespace(INamespaceSymbol namespaceSymbol)
    {
        WriteIndentation();
    }

    public override void WriteNamespaceDefinition(INamespaceSymbol namespaceSymbol, SymbolDisplayFormat format = null)
    {
        if (namespaceSymbol.IsGlobalNamespace)
            return;

        WriteDocumentationComment(namespaceSymbol);
        WriteDefinition(namespaceSymbol, format);
        WriteLine();
        IncreaseDepth();
    }

    public override void WriteEndNamespace(INamespaceSymbol namespaceSymbol)
    {
        if (namespaceSymbol.IsGlobalNamespace)
            return;

        DecreaseDepth();
    }

    public override void WriteEndTypes()
    {
    }

    public override void WriteStartType(INamedTypeSymbol typeSymbol)
    {
        WriteIndentation();
    }

    public override void WriteTypeDefinition(INamedTypeSymbol typeSymbol, SymbolDisplayFormat format = null)
    {
        if (typeSymbol is not null)
        {
            WriteDocumentationComment(typeSymbol);
            WriteDefinition(typeSymbol, format);
        }

        WriteLine();

        IncreaseDepth();
    }

    public override void WriteEndType(INamedTypeSymbol typeSymbol)
    {
        DecreaseDepth();
    }

    public override void WriteEndMembers()
    {
    }

    public override void WriteStartMember(ISymbol symbol)
    {
        WriteIndentation();
    }

    public override void WriteMemberDefinition(ISymbol symbol, SymbolDisplayFormat format = null)
    {
        WriteDocumentationComment(symbol);
        WriteDefinition(symbol, format);
        WriteLine();
        IncreaseDepth();
    }

    public override void WriteEndMember(ISymbol symbol)
    {
        DecreaseDepth();
    }

    public override void WriteEndEnumMembers()
    {
    }

    public override void WriteStartEnumMember(ISymbol symbol)
    {
        WriteIndentation();
    }

    public override void WriteEnumMemberDefinition(ISymbol symbol, SymbolDisplayFormat format = null)
    {
        WriteDocumentationComment(symbol);
        WriteDefinition(symbol, format);

        if (Format.Includes(SymbolDefinitionPartFilter.TrailingComma))
            Write(",");

        WriteLine();
        IncreaseDepth();
    }

    public override void WriteEndEnumMember(ISymbol symbol)
    {
        DecreaseDepth();
    }

    public override void WriteStartAttributes(ISymbol symbol)
    {
        Write("[");
    }

    public override void WriteEndAttributes(ISymbol symbol)
    {
        Write("]");

        if (symbol.Kind == SymbolKind.Assembly || SupportsMultilineDefinitions)
        {
            WriteLine();
        }
        else
        {
            Write(" ");
        }
    }

    public override void WriteStartAttribute(AttributeData attribute, ISymbol symbol)
    {
    }

    public override void WriteEndAttribute(AttributeData attribute, ISymbol symbol)
    {
    }

    public override void WriteAttributeSeparator(ISymbol symbol)
    {
        if (symbol.Kind == SymbolKind.Assembly
            || (Format.Includes(WrapListOptions.Attributes) && SupportsMultilineDefinitions))
        {
            Write("]");
            WriteLine();
            Write("[");
        }
        else
        {
            Write(", ");
        }
    }

    public override void WriteDefinition(ISymbol symbol, SymbolDisplayFormat format)
    {
        if (Format.Includes(SymbolDefinitionPartFilter.Attributes))
            WriteAttributes(symbol);

        base.WriteDefinition(symbol, format);
    }
}
